﻿using OpenTK.Math;
using OpenTK.Graphics;
using System;
using System.Runtime.InteropServices;

namespace Rekx.Graphics
{
    /// <summary>
    /// Represents the basic geometry that can be drawn with a given effect and texture. 
    /// This includes vertecies, indices, normals, texcoords etc.
    /// </summary>
    internal class Geometry : IDisposable
    {
        private int numElements;
        private VertexBuffer vertexBuffer;
        private IndexBuffer indexBuffer;
        private TexCoordBuffer texCoordBuffer;

        public int NumElements
        {
            get
            {
                return numElements;
            }
        }

        public Geometry(Vector3[] vertices, int[] indices, Vector2[] texCoords)
        {           

            vertexBuffer = new VertexBuffer(vertices);
            indexBuffer = new IndexBuffer(indices);
            texCoordBuffer = new TexCoordBuffer(texCoords);


            numElements = indices.Length;            
        }

        /// <summary>
        /// Binds the Geometry data to the opengl state
        /// </summary>
        public void Bind()
        {
            // bind the buffers
            vertexBuffer.Bind();
            GL.VertexPointer(3, VertexPointerType.Float, Vector3.SizeInBytes, IntPtr.Zero);
            texCoordBuffer.Bind();
            GL.TexCoordPointer(3, TexCoordPointerType.Float, Marshal.SizeOf(new Vector2()), IntPtr.Zero);
            indexBuffer.Bind();
        }

        /// <summary>
        /// Unbinds the geometry from the opengl state
        /// </summary>
        public void UnBind()
        {
            // unbind the buffers
            vertexBuffer.UnBind();
            indexBuffer.UnBind();
        }

        #region IDisposable Pattern
        // taken from msdn

        private bool disposed = false;

        // Implement IDisposable.
        // Do not make this method virtual.
        // A derived class should not be able to override this method.
        public void Dispose()
        {
            Dispose(true);
            // This object will be cleaned up by the Dispose method.
            // Therefore, you should call GC.SupressFinalize to
            // take this object off the finalization queue
            // and prevent finalization code for this object
            // from executing a second time.
            GC.SuppressFinalize(this);
        }

        // Dispose(bool disposing) executes in two distinct scenarios.
        // If disposing equals true, the method has been called directly
        // or indirectly by a user's code. Managed and unmanaged resources
        // can be disposed.
        // If disposing equals false, the method has been called by the
        // runtime from inside the finalizer and you should not reference
        // other objects. Only unmanaged resources can be disposed.
        private void Dispose(bool disposing)
        {
            // Check to see if Dispose has already been called.
            if (!this.disposed)
            {
                // If disposing equals true, dispose all managed
                // and unmanaged resources.
                if (disposing)
                {
                    // Dispose managed resources.
                    vertexBuffer.Dispose();
                    indexBuffer.Dispose();
                    texCoordBuffer.Dispose();
                }

                // Call the appropriate methods to clean up
                // unmanaged resources here.
                // If disposing is false,
                // only the following code is executed.
                

                // Note disposing has been done.
                disposed = true;

            }
        }

        #endregion
    }
}
